/***
 * @Author: 玄绮 shijiahansi@qq.com
 * @Date: 2024-05-16 15:38:20
 * @LastEditors: 玄绮 shijiahansi@qq.com
 * @LastEditTime: 2024-05-16 15:38:20
 * @FilePath: \boost_chat\src\client\app\Client.cpp
 * @Description:
 * @
 * @Copyright (c) 2024 by 玄绮, All Rights Reserved.
 */
#include "Client.h"

#include "data/UserInfo.pb.h"

#include <boost/smart_ptr/make_shared_object.hpp>
#include <boost/system/detail/error_code.hpp>
#include <iostream>
#include <ostream>
#include <string>
#include <vector>

Client::Client(std::string_view host, int port) {
    this->host = host;
    this->port = port;
    start_console();
    try {
        reconnect_server(host, port);
    }
    catch (const std::exception& e) {
        std::cerr << e.what() << '\n';
    }
}
bool Client::connect_server(std::string_view address, int port) {
    return reconnect_server(address, port);
}

bool Client::reconnect_server(std::string_view address, int port) {
    try {
        endpoint_type ep(boost::asio::ip::make_address_v4(address), port);
        std::cout << "address:" << address << std::endl;
        std::cout << "port:" << port << std::endl;

        sock = boost::make_shared<socket_type>(ctx);

        boost::system::error_code ec;
        sock->connect(ep, ec);
        if (!ec) {
            do_read();
        }
        else {
            std::cout << ec.message() << std::endl;
            handle_error(ec);
        }
    }

    catch (const boost::system::system_error& e) {
        std::cerr << "Boost System Error: " << e.what() << std::endl;
        handle_error(e.code());
    }
    catch (const std::exception& e) {
        std::cerr << "Standard Exception: " << e.what() << std::endl;
    }
    catch (...) {
        std::cerr << "Unknown error occurred." << std::endl;
    }
    return true;
}
void Client::do_read() {
    async_read(*sock,
        [this](boost::system::error_code ec, proto::packge::Packge::shared_ptr pack) {
            if (ec) {
                std::cerr << "read pack:" << ec.what() << std::endl;
                handle_error(ec);
                return;
            }
            pack_handler(pack);
            do_read();
        });
}

void Client::handler_system_category(const boost::system::error_code& ec) {
    switch (ec.value()) {
        case 10009:  // 提供的文件句柄无效。
        case 10060:  // 由于连接方在一段时间后没有正确答复或连接的主机没有反应，连接尝试失败。
        case 10065:  // 套接字操作尝试一个无法连接的主机。
        case 10054:  // 远程主机强迫关闭了一个现有的连接。

        default:
            break;
    }
}

void Client::handle_error(const boost::system::error_code& ec) {
    if (ec) {
        std::cout << "Error code: " << ec.value() << "\n";
        std::cout << "Error message: " << ec.message().c_str() << "\n";
        const boost::system::error_category& cat = ec.category();

        if (cat == boost::system::system_category()) {
            std::cout << "Error category: system\n";
        }
        else if (cat == boost::system::generic_category()) {
            std::cout << "Error category: generic\n";
            handler_system_category(ec);
        }
        else {
            std::cout << "Error category: other\n";
        }
    }
    else {
        std::cout << "No error\n";
    }
}
void Client::run() {
    ctx.run();
};

void Client::send_packge(::proto::packge::Packge::shared_ptr pack) {
    std::string ss;
    pack->SerializeToString(ss);
    async_send(*sock, pack, [=](boost::system::error_code ec, size_t size) {
        if (ec) {
            handle_error(ec);
        }
    });
}

void Client::onMessage(std::shared_ptr<proto::data::Message> msg) {
    std::cout << msg->DebugString() << std::endl;
}

void Client::onRegister(int code, String message, std::shared_ptr<UserInfo> user) {

};

void Client::onLogin(int code, String message, std::shared_ptr<UserInfo> user) {
    if (!code) {
        myself   = *user;
        is_login = !code;

        GetFriendList();
        GetRoomList();
        std::cout << "登录成功" << std::endl;
    }
    else {
        std::cout << message << std::endl;
    }
};

void Client::onGetUserInfo(int code, String message, std::shared_ptr<UserInfo> user) {};

void Client::onChangUserInfo(int code, String message, std::shared_ptr<UserInfo> user) {};

void Client::onSearchAuthor(int code, String message, std::vector<std::shared_ptr<UserInfo>> users) {};

void Client::onSearchGroup(int code, String message, std::vector<std::shared_ptr<ChatRoomInfo>> rooms) {};

void Client::onAddFriends(int code, String message, std::shared_ptr<FriendInfo> info) {};

void Client::onDelFriends(int code, String message, String firendsId) {};

void Client::onCreateGroup(int code, String message, std::shared_ptr<ChatRoomInfo> room) {};

void Client::onCreateRoom(int code, String message, std::shared_ptr<ChatRoomInfo> room) {};

void Client::onJoinGroup(int code, String message, std::shared_ptr<ChatRoomInfo> room) {};

void Client::onQuitGroup(int code, String message, String roomId) {};

void Client::onSetAccount(int code, String message) {};

void Client::onSetUserInfo(int code, String message, std::shared_ptr<UserInfo> user) {};

void Client::onGetFriendList(int code, String message, std::vector<std::shared_ptr<FriendInfo>> users) {};

void Client::onGetRoomList(int code, String message, std::vector<std::shared_ptr<ChatRoomInfo>> rooms) {}

void Client::onGetRoomMembers(int code, String message, String roomId, std::vector<std::shared_ptr<UserInfo>>) {};

void Client::cmd_work(std::string& line) {
    static std::vector<std::string> list;
    boost::split(list, line, boost::is_any_of(" "));
    auto& cmd = list[0];
    try {
        switch (app_status) {
            case AppStatus::APP_Message_GROUP: {
                if (cmd == ":list") {
                    static boost::format fmt("\t%-7s%-10s%-10s\n");
                    std::cout << fmt % "ID" % "NAME" % "SIGN";
                    if (list[1] == "member") {
                        for (auto&& i : chat_room->_members) {
                            auto& u = i;

                            std::cout << fmt % u.userid() % u.name() % u.sign();
                        }
                        std::cout << std::endl;
                        return;
                    }
                }
            }

            break;
            default:
                break;
        }

        common_cmd(line, list);
    }
    catch (const std::exception& e) {
        std::cerr << e.what() << '\n';
    }
}

void Client::common_cmd(std::string& line, std::vector<std::string>& list) {
    auto& cmd = list[0];
    if (cmd == ":home") {
        app_status = AppStatus::APP_Home;
        return;
    }
    // login acount password
    if (cmd == ":login") {
        if (is_login) {
            std::cout << "你已经登录" << std::endl;
            return;
        }
        Login(list[1], list[2]);
        return;
    }

    if (cmd == ":register") {
        proto::data::RegisterInfo info;
        std::cout << "mail:";
        std::cout.flush();
        std::cin >> *info.mutable_bind();
        std::cout << "account:";
        std::cout.flush();
        std::cin >> *info.mutable_account();
        std::cout << "password:";
        std::cout.flush();
        std::cin >> *info.mutable_password();

        Register(info);
        return;
    }

    if (cmd == ":search") {
        auto& item = list[1];
        if (item == "author") {
            SearchAuthor(list[2]);
        }
        else if (item == "room") {
            SearchGroup(list[2]);
        }
        else
            std::cout << "查询条件不存在：" << item << std::endl;
        return;
    }

    if (cmd == ":create") {
        if (list[1] == "room") {
            proto::data::ChatRoomInfo info;
            std::cout << "roomid:";
            std::cout.flush();
            std::cin >> *info.mutable_roomid();
            std::cout << "name:";
            std::cout.flush();
            std::cin >> *info.mutable_name();
            std::cout << "sign:";
            std::cout.flush();
            std::cin >> *info.mutable_sign();

            CreateGroup(info);
            return;
        }

        std::cout << ":create 没有该选项 [ " << list[1] << " ] " << std::endl;
    }

    if (cmd == ":join") {
        auto& room_id = list[1];

        JoinGroup(room_id);
        return;
    }

    if (cmd == ":add") {
        if (is_login) {
            AddFriends(list[1]);
            return;
        }
    }
    if (cmd == ":del" || cmd == ":delete") {
        if (is_login) {
            DelFriends(list[1]);
            return;
        }
    }

    if (cmd == ":unlogin") {
        // 一下指令仅在登录后可以使用
        if (is_login == false)
            std::cout << "你还没有登录" << std::endl;
        else {
            std::cout << "退出登录" << std::endl;
            app_status = AppStatus::APP_Home;
            is_login   = false;
            exit(0);
        }
        return;
    }

    if (cmd == ":list") {
        auto& item = list[1];
        if (item == "firends") {
            static boost::format fmt("\t%-7s%-10s%-10s\n");
            std::cout << fmt % "ID" % "NAME" % "SIGN";
            for (auto& i : firends) {
                auto& u = i.second;
                std::cout << fmt % u.userid() % u.name() % u.sign();
            }
            std::cout << std::endl;
            return;
        }

        if (item == "room") {
            static boost::format fmt("\t%-7s%-10s%-10s\n");
            std::cout << fmt % "ID" % "NAME" % "SIGN";
            for (auto& i : rooms) {
                auto& u = i.second;
                std::cout << fmt % u->roomid() % u->name() % u->sign();
            }
            std::cout << std::endl;
            return;
        }

        return;
    }

    // message to_user_id
    if (cmd == ":message") {
        auto& userid = list[1];
        std::cerr << "正在与 [" << userid << "]聊天" << std::endl;

        for (auto&& i : firends) {
            auto& u = i.second;
            if (u.userid() == userid) {
                app_status = AppStatus::APP_Message_PTOP;
                chat_user  = &u;
                return;
            }
        }
        for (auto&& i : rooms) {
            auto& u = i.second;
            if (u->roomid() == userid) {
                app_status = AppStatus::APP_Message_GROUP;
                chat_room  = u;
                GetRoomMembers(u->roomid());
                return;
            }
        }

        std::cout << "该用户还不是你好友" << std::endl;
        return;
    }
    std::cout << "指令不存在，或当前状态不可用" << std::endl;
}

void Client::home_work(std::string& line) {
}

void Client::message_work_PTOP(std::string& line) {
    auto msg = proto::data::Message{};
    msg.set_to_user_id(chat_user->userid());
    msg.set_from_user_id(myself.userid());
    msg.set_text(line);
    msg.set_type(::proto::data::Message_Type::Message_Type_PTOP);

    send_pack(msg, PackgeType::Message);
}

void Client::message_work_GROUP(std::string& line) {
    auto msg = proto::data::Message{};
    msg.set_to_user_id(chat_room->roomid());
    msg.set_from_user_id(myself.userid());
    msg.set_text(line);
    msg.set_type(::proto::data::Message_Type::Message_Type_GROUP);

    send_pack(msg, PackgeType::Message);
}

void Client::verificationCode(std::string& line) {
    if (line == "resend") {
        ResendVerificationCode();
    }
    else {
        SendVerificationCode(line);
    }
}

void Client::read_console() {
    std::string line;

    while (1) {
        std::getline(std::cin, line);
        if (line == "")
            continue;
        line.erase(line.find_first_of('\r'));
        if (line[0] == ':') {
            cmd_work(line);
            continue;
        }
        switch (app_status) {
            case AppStatus::APP_Home:
                home_work(line);
                break;

            case AppStatus::APP_Message_PTOP:
                message_work_PTOP(line);
                break;
            case AppStatus::APP_Message_GROUP:
                message_work_GROUP(line);
                break;

            case AppStatus::APP_VerificationCode:
                verificationCode(line);
                break;
        }
    }
}

void Client::start_console() {
    t_console = std::thread([this]() {
        read_console();
    });
}